<?php
class addressbook_processor extends sharpobj_processor
{
    // ***********************************************
    // Инициализация
    
    // Исталляция
    protected function act_createTables()
    {
        // Персоны
        $this->storageLink('persones')->sqlqueryAction("CREATE TABLE #!table# (
  `id` int(11) NOT NULL auto_increment COMMENT 'ключ',
  `first` varchar(100) collate utf8_unicode_ci default NULL COMMENT 'имя',
  `last` varchar(100) collate utf8_unicode_ci default NULL COMMENT 'фамилия',
  `middle` varchar(100) collate utf8_unicode_ci default NULL COMMENT 'отчество',
  `suffix` varchar(100) collate utf8_unicode_ci default NULL COMMENT 'суффикс',
  `formaddr` varchar(100) collate utf8_unicode_ci default NULL COMMENT 'форма обращения',
  `format` varchar(10) collate utf8_unicode_ci default NULL COMMENT 'формат (порядок расстановки: afmsl)',
  `gender` enum('male','female') NOT NULL COMMENT 'пол',
  `fullname` varchar(255) collate utf8_unicode_ci default NULL COMMENT 'полное имя, в соответствии с форматом (для сортировки))',
  `del` smallint(1) NOT NULL default '0' COMMENT 'Если удален - 1',
  PRIMARY KEY  (`id`),
KEY `k_del` ( `del` ),
KEY `k_fullname` ( `fullname` )
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Персоналии';");
        
        // Группы
        $this->storageLink('pgroups')->sqlqueryAction("CREATE TABLE #!table# (
`id` INT NOT NULL AUTO_INCREMENT,
`parent` INT NULL ,
`name` VARCHAR( 100 ) NOT NULL ,
`child_cache` TEXT NULL ,
PRIMARY KEY  (`id`),
KEY `k_parent` ( `parent` )
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT = 'Группы контактов';");
		
		// Ассоциации объектов с экземплярами г шруппы дополнительных полей
        $this->storageLink('groupmembers')->sqlqueryAction("CREATE TABLE #!table# (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`p_id` INT NOT NULL, 
`g_id` INT NOT NULL
) ENGINE = MYISAM   CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT = 'Ассоциации пользователей с группами системы';");
 
        /*
        // Классы дополнительных полей
        $this->storageLink('addf_cls')->sqlqueryAction("CREATE TABLE #!table# (
`id` INT NOT NULL AUTO_INCREMENT,
`code` VARCHAR( 100 ) NOT NULL ,
`pers` enum('0','1') NOT NULL default '0',
`org` enum('0','1') NOT NULL default '0',
PRIMARY KEY  (`id`),
UNIQUE KEY  `code` ( `code` )
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT = 'Классы дополнительных полей';");
        */
        // Экземпляры классов дополнительных полей
        $this->storageLink('addf_inst')->sqlqueryAction("CREATE TABLE #!table# (
`id` INT NOT NULL AUTO_INCREMENT ,
`cls_code` VARCHAR( 100 ) NOT NULL ,
`code` VARCHAR( 100 ) NOT NULL ,
`title` VARCHAR( 255 ) NOT NULL ,
`pers` enum('0','1') NOT NULL default '0',
`org` enum('0','1') NOT NULL default '0',
PRIMARY KEY  (`id`),
KEY `k_cls_code` (`cls_code`),
UNIQUE KEY  `k_code` ( `code` )
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT = 'Экземпляры классов доп. полей';");
        // Ассоциации объектов с экземплярами классов дополнительных полей
        $this->storageLink('addf_assoc')->sqlqueryAction("CREATE TABLE #!table# (
`id` INT NOT NULL AUTO_INCREMENT,
`inst_id` INT NOT NULL ,
`o_id` INT NOT NULL ,
`type` enum('pers','org') NOT NULL,
PRIMARY KEY  (`id`),
KEY ( `o_id` ),
KEY ( `type` ),
UNIQUE KEY  `k_oinst` ( `inst_id`,`o_id`,`type`)
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT = 'Ассоциации объектов с экземплярами классов доп. полей';");

        // Ассоциации объектов с экземплярами классов дополнительных полей
        $this->storageLink('addf_cls_users')->sqlqueryAction("CREATE TABLE #!table# (
`id` INT NOT NULL AUTO_INCREMENT,
`assoc_id` INT NOT NULL,
`user_id` INT NOT NULL ,
PRIMARY KEY  (`id`),
KEY ( `user_id` ),
UNIQUE KEY  `k_assoc` ( `assoc_id`)
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_unicode_ci COMMENT = 'Ассоциации объектов с пользователями системы';");
        
        
    }
    protected function act_dropTables()
    {
        //
        $this->storageLink('persones')->sqlqueryAction("DROP TABLE #!table#;");
        $this->storageLink('pgroups')->sqlqueryAction("DROP TABLE #!table#;");
		$this->storageLink('groupmembers')->sqlqueryAction("DROP TABLE #!table#;");
        // $this->storageLink('addf_cls')->sqlqueryAction("DROP TABLE #!table#;");
        $this->storageLink('addf_inst')->sqlqueryAction("DROP TABLE #!table#;");
        $this->storageLink('addf_assoc')->sqlqueryAction("DROP TABLE #!table#;");
        $this->storageLink('addf_cls_users')->sqlqueryAction("DROP TABLE #!table#;");
       

    }

    function __construct($pref='addressbook_')
    {
        // Создаем справочники
        // Задаем формат справочников
      
                        
        // ***Персоналии***
        // Объявляем формат
        $persones_format = new sharpobj_storage_format();
        // Имя
        $persones_format->addItem('first','first','row');
        // Фамилия
        $persones_format->addItem('last','last','row');
        // Отчество
        $persones_format->addItem('middle','middle','row');
        // Суффикс
        $persones_format->addItem('suffix','suffix','row');
        // Форма обращения
        $persones_format->addItem('formaddr','formaddr','row');
        // Формат
        $persones_format->addItem('format','format','smallatword');
        // Пол
        $persones_format->addItem('gender','gender','smallatword');
        // Полное имя, в соответствии с форматом
        $persones_format->addItem('fullname','fullname','row');
        // Удален?
        $persones_format->addItem('del','del','int');
        // Объявляем справочник
        $this->storageAdd
                        (
							'persones', 
                            new sharpobj_storage_mysql
                            (
                                $persones_format,
                                array(
										'tbname'=>$pref.'persones',
										'idfield'=>'id'
                                      )
                            )
                        );

        // ***Персоналии***
        // Объявляем формат
        $fpersones_format = clone $persones_format;
        $fpersones_format->addItem('cls','cls','data');
		$fpersones_format->addItem('grp','grp','data');
        // Объявляем справочник
        $this->storageAdd
                        (
							'fpersones', 
                            new sharpobj_storage_adapter
                            (
                                $fpersones_format
                            )
                        );
             
        // ***Группы***
        // Объявляем формат
        $pgroups_format = new sharpobj_storage_format();
        $pgroups_format->addItem('parent','parent','int');
        $pgroups_format->addItem('name','name','row');
        $pgroups_format->addItem('child_cache','child_cache','string');
        // Объявляем справочник
        $this->storageAdd
                        (
							'pgroups', 
                            new sharpobj_storage_mysql
                            (
                                $pgroups_format,
                                array(
										'tbname'=>$pref.'pgroups',
										'idfield'=>'id'
                                      )
                            )
                        );
        // ***Запись пользователя в группу***
        // Объявляем формат
        $groupmembers_format = new sharpobj_storage_format();
        $groupmembers_format->addItem('p_id','p_id','int');
        $groupmembers_format->addItem('g_id','g_id','int');
        // Объявляем справочник
        $this->storageAdd
                        (
							'groupmembers', 
                            new sharpobj_storage_mysql
                            (
                                $groupmembers_format,
                                array(
										'tbname'=>$pref.'groupmembers',
										'idfield'=>'id'
                                      )
                            )
                        );
        /*
        // ***Классы дополнительных полей***
        // Объявляем формат
        $addf_cls_format = new sharpobj_storage_format();
        // Код класса
        $addf_cls_format->addItem('code','code','smallatword');
        // Подходит для персон
        $addf_cls_format->addItem('pers','pers','int');
        // Подходит для организаций
        $addf_cls_format->addItem('org','org','int');
        // Объявляем справочник
        $this->storageAdd
                        (
							'addf_cls', 
                            new sharpobj_storage_mysql
                            (
                                $addf_cls_format,
                                array(
										'tbname'=>$pref.'addf_cls',
										'idfield'=>'id'
                                      )
                            )
                        );
		*/
        // ***Экземпляры классов дополнительных полей***
        // Объявляем формат
        $addf_inst_format = new sharpobj_storage_format();
        // id класса
        // $addf_inst_format->addItem('cls_id','cls_id','int');
        // Код класса
        $addf_inst_format->addItem('cls_code','cls_code','smallatword');
        // Код экземпляра
        $addf_inst_format->addItem('code','code','smallatword');
        // Заголовок экземпляра
        $addf_inst_format->addItem('title','title','row');
        // Подходит для персон
        $addf_inst_format->addItem('pers','pers','int');
        // Подходит для организаций
        $addf_inst_format->addItem('org','org','int');
        // Объявляем справочник
        $this->storageAdd
                        (
							'addf_inst', 
                            new sharpobj_storage_mysql
                            (
                                $addf_inst_format,
                                array(
										'tbname'=>$pref.'addf_inst',
										'idfield'=>'id'
                                      )
                            )
                        );
        // ***Ассоциация Объектов с экземплярами классов***
        // Объявляем формат
        $addf_assoc_format = new sharpobj_storage_format();
        // id экземпляра
        $addf_assoc_format->addItem('inst_id','inst_id','int');
        // id персоны
        $addf_assoc_format->addItem('o_id','o_id','int');
        // Тип ассоциации
        $addf_assoc_format->addItem('type','type','smallatword');
        // Объявляем справочник
        $this->storageAdd
                        (
							'addf_assoc', 
                            new sharpobj_storage_mysql
                            (
                                $addf_assoc_format,
                                array(
										'tbname'=>$pref.'addf_assoc',
										'idfield'=>'id'
                                      )
                            )
                        );
        // ***Ассоциация объекта с пользователем***
        // Объявляем формат
        $addf_cls_users_format = new sharpobj_storage_format();
        // id ассоциации
        $addf_cls_users_format->addItem('assoc_id','assoc_id','int');
        // id пользователя
        $addf_cls_users_format->addItem('user_id','user_id','int');
        // Объявляем справочник
        $this->storageAdd
                        (
							'addf_cls_users', 
                            new sharpobj_storage_mysql
                            (
                                $addf_cls_users_format,
                                array(
										'tbname'=>$pref.'addf_cls_users',
										'idfield'=>'id'
                                      )
                            )
                        );
        /*
        // ***Классы дополнительных полей***
        // Объявляем формат
        $classes_format = new sharpobj_storage_format();
        // Название класса
        $classes_format->addItem('name','name','row');
        // Тип класса
        $classes_format->addItem('type','type','row');
        // Объявляем справочник
        $this->storageAdd
                        (
							'classes', 
                            new sharpobj_storage_mysql
                            (
                                $groups_format,
                                array(
										'tbname'=>$pref.'classes',
										'idfield'=>'id'
                                      )
                            )
                        );
		*/
    }
    protected $addf_classes=null;
    protected function addfLink($code)
    {
        $cfg_addf = mst_getcfgmod('addressbook','cfg_addf');
        if (!isset($cfg_addf[$code]))
        {
            // Такой код в конфиге отсутствует
            return false;
        }
        // Возвращаем ссылку
        if (isset($this->addf_classes[$code]))
        {
            // Возвращаем ссылку на существующий экземпляр
            return $this->addf_classes[$code];
        }else
        {
            // Создаем новый экземпляр
            if (isset($cfg_addf[$code]['mod'])
                AND $cfg_addf[$code]['mod'])
            {
                // Нужно загрузить модуль
                mst_initmod($cfg_addf[$code]['mod']);
                $class_name = $cfg_addf[$code]['class'];
            }else
            {
                // Класс определен в модуле адрессной книги
                mst_modfileload('addressbook',"class/{$code}.php");
                $class_name = "addressbook_addf_{$code}";
            }
            // Создаем экземпляр класса
            return $this->addf_classes[$code] = new $class_name($this,$cfg_addf[$code]);
        }
    }
    protected function act_addAddf($code,$mod,$class,$cfg=null)
    {
        mst_initmod($mod->getP());
        // Подключаем класс
        $class_name = $class->getP();
        if ($cfg)
        {
            $cfg_a = $cfg->getP();
        }else
        {
            $cfg_a = null;    
        }
        $this->addf_classes[$code->getP()] = new $class_name($this,$cfg_a);
        return true;
    }
	/**
	 * Получить информацию о персоне
	 */
    protected function act_getPerson($id)
    {
        $id = sharpobj_conv_int_obj($id);
        // $obj = $this->storageLink('fpersones')->getObj();
        $obj = $this->storageLink('persones')->get($id);
        // Добавляем поле для хранения информации классов
        $obj->addItem('cls','data');
        
		// Получаем список дополнительных полей
        $class_list = $this->storageLink('addf_assoc')->getListFilter(array('type'=>'pers','o_id'=>$id->getP()));
        // print_r($class_list);
        foreach ($class_list as $cls_obj)
        {
            $inst = $this->storageLink('addf_inst')->get($cls_obj->getP('inst_id'));
            $item_obj =  $this->addfLink($inst->getP('cls_code'))->get($cls_obj->getId());
            // Добавляем информацию в объект
            $obj->addItem('cls/'.$inst->getP('cls_code'),$item_obj);
        }
		// Получаем список групп
		
		// Возвращаем объект
        return $obj;
    }
	/**
	 * Сохранить информацию о персоне
	 */
    protected function act_savePerson(sharpobj_data_item_data $obj)
    {
    	// Формируем полное имя
    	$obj->set('plain',addressbook_pname($obj),'fullname');
        // Сохраняем запись о персоне
        if ($obj->getId())
        {
            // Обновить
            $id = $this->storageLink('persones')->update($obj);
        }else
        {
            $id = $this->storageLink('persones')->insert($obj);
            $obj->setId(sharpobj_conv_obj_int($id));
        }
        // Сохраняем информацию о дополнительных классах
        if ($obj->isData('cls'))
        {
            $cls = $obj->cloneItem('cls');
            foreach ($cls as $cls_name=>$cls_obj)
            {
                // echo $cls_name;var_dump($cls_obj);
                // Получаем экземпляр, соответствующий коду экземпляра
                $inst = $this->pvtact_getInst($cls_name);
                // $inst = $this->storageLink('addf_inst')->sqlqueryGet(" WHERE `code`='".addslashes($cls_name)."'");
                if (!$inst or sharpobj_iserror($inst))
                {
                    // Экземпляр не найден или ошибка sql-запроса
                    continue;
                }
                // Зарегистрировать ассоциацию объекта с экземпляром класса
                $assoc_id = $this->act_saveAddfAssoc(
                        sharpobj_conv_array_obj(
                            array('type'=>'pers','o_id'=>$obj->getId(),'inst_id'=>$inst->getId()
                                        )
                                    )
                                );
                // Сохранить информацию
                $this->addfLink($inst->getP('cls_code'))->save($cls_obj,$assoc_id);
                // var_dump($cls_name);
                // var_dump($cls_obj);
            }
        }
        return $id;
    }
	/**
	 * Удалить персону
	 */
    protected function act_deletePerson($id)
    {
        $id = sharpobj_conv_int_obj($id);
        // $obj = $this->storageLink('fpersones')->getObj();
        // $obj = $this->storageLink('persones')->get($id);
       
        $class_list = $this->storageLink('addf_assoc')->getListFilter(array('type'=>'pers','o_id'=>$id->getP()));
        // print_r($class_list);
        foreach ($class_list as $cls_obj)
        {
            $this->pvtact_deleteAddfAssoc($cls_obj->getId());
        }
        return $this->storageLink('persones')->delete($id);;
    }
    /**
	 * Получить отформатированное имя персоны
	 */
    protected function act_getPersonName($obj)
    {
        return sharpobj_conv_row_obj(addressbook_pname($obj));
    }

    /**
     * Сохранение и получение id ассоциации с экземпляром класса
     */
    protected function act_saveAddfAssoc($obj)
    {   
        if ($id = $this->storageLink('addf_assoc')->sqlqueryOneValueInt(
											"SELECT #!table#.`id` FROM #!table# "
                                            ." WHERE `inst_id`='{$obj->get('sql','inst_id')}' "
                                            ." AND `type`='{$obj->get('sql','type')}' "
                                            ." AND `o_id`='{$obj->get('sql','o_id')}' "
                                            ." LIMIT 1"))
        {
            // Объект уже создан
            return sharpobj_conv_int_obj($id); 
        }else
        {
            // Создаем объект
            return $this->storageLink('addf_assoc')->insert($obj);
        }
        
    }
	/**
	 * 	Определено ли для персоны дополнительное поле
	 * @param $obj
	 * @return bool
	 */
	protected function act_isPerson2Addf($obj)
	{
		if ($obj->isExists('code')
			AND $obj->isData('code'))
		{
			// Нам передали код
			$inst = $this->pvtact_getInst($obj->getP('code'));
			if (!$inst or sharpobj_iserror($inst))
			{
				// Такого кода не найдено
				return false;
			}
			$inst_id = sharpobj_conv_int_obj($inst->getId());
		}else
		{
			// Нам передали id
			$inst_id = $obj->cloneItem('inst_id');
		}
		return $this->pvtact_isObj2Addf('pers',
											$obj->cloneItem('o_id'),
											$inst_id);
	}
	/**
	 * Создать группу
	 *
	 * @param sharpobj_data_item_data $obj
	 * @return int group_id
	 */
	protected function act_savePGroup($obj)
	{
	// Сохраняем\создаем группу
        if ($obj->getId())
        {
            // Обновить
            $id = $this->storageLink('pgroups')->update($obj);
        }else
        {
            $id = $this->storageLink('pgroups')->insert($obj);
            if (sharpobj_iserror($id))
            {
            	echo('Ошибка');
            	return false;
            }
            //$obj->setId(sharpobj_conv_obj_int($id));
        }
		return $id;
	}
	/**
	 * Записать персону в группу
	 */
	protected function act_includePGroupMember($obj)
	{
		 $id=$this->storageLink('groupmembers')->insert($obj);
		if (sharpobj_iserror($id))
        {
           	echo('Ошибка');
           	return false;
        }else
        {
        	return true;
        }
   	}
	/**
	 * Исключить персону из группы
	 */
	protected function act_excludePGroupMember($obj)
	{
			$do=false;
			if($del = $this->storageLink('groupmembers')->sqlqueryGet(" WHERE `p_id`='{$obj->getP('p_id')}' AND `g_id`='{$obj->getP('g_id')}'"))
				{
					//echo ($del->getId());
					if($this->storageLink('groupmembers')->delete($del->getId()))
					{
						 $do=true;
					}
				}
			return $do;
	}
	/**
	 * Получить список членов данной группы и ее подгрупп
	 */
	protected function act_listPGroupMember($obj)
	{	
		//передали id группы
		$id=sharpobj_conv_obj_int($obj);
		$list = $this->storageLink('groupmembers')->sqlquerylist("SELECT #!id# FROM #!table#  WHERE `g_id`='{$id}'");
		$list2 = $this->storageLink('pgroups')->sqlquerylist("SELECT #!id# FROM #!table#  WHERE `parent`='{$id}'"); 
		$all=array();
		foreach ($list as $one)
		{
		 		array_push($all,intval($one->getId()));	
		}
		foreach ($list2 as $two)
		{
				array_push($all,intval($two->getId()));	
		}
		return $all;
	}
	/**
	 * Получить список членов данной группы
	 */
	protected function act_listPGroupMemberStrong($obj)
	{
		$id=sharpobj_conv_obj_int($obj);
		$list=$this->storageLink('groupmembers')->sqlquerylist(" SELECT #!id# FROM #!table#  WHERE `g_id`='{$id}'");
	if (sharpobj_iserror($list))
        {
           	echo('Ошибка');
           	return false;
        }else
        {
        	return $list;
        }
		
		
		
	}
	/**
	 * Проверить, является ли персона членом группы или ее подгрупп
	 */
	protected function act_isPGroupMember($obj)
	{
		//
	}
	/**
	 * Проверить, является ли персона членом данной группы
	 *
	 * @param sharpobj_data_item_data $obj
	 */
	protected function act_isPGroupMemberStrong($obj)
	{
		$member=($this->storageLink('groupmembers')->sqlquerylist("SELECT #!id# FROM #!table# WHERE `p_id`='{$obj->getP('p_id')}' AND `g_id`='{$obj->getP('g_id')}'"));
		if (sharpobj_iserror($member))
		{
			echo('Ошибка');
			return false;
		}else
		{
			return true;
		}
	}
	/**
	 * Проверка, определены ли для персоны/организации дополнительные поля	
	 * @param $type
	 * @param $o_id
	 * @param $inst_id
	 * @return bool
	 */
	protected function pvtact_isObj2Addf($type,$o_id,$inst_id)
	{
		$type = sharpobj_conv_smallatword_obj($type);
		$o_id = sharpobj_conv_int_obj($o_id);
		$inst_id = sharpobj_conv_int_obj($inst_id);
		$res = $this->storageLink('addf_assoc')->sqlqueryOneValueInt(
											"SELECT COUNT(*) FROM #!table# "
                                            ." WHERE `inst_id`='{$inst_id->get('sql')}' "
                                            ." AND `type`='{$type->get('sql')}' "
                                            ." AND `o_id`='{$o_id->get('sql')}' ");
		if ($res > 0 AND !sharpobj_iserror($res))
		{
			return true;
		}else
		{
			return false;
		}
	}
	protected function pvtact_getInst($code)
	{
		$code = sharpobj_conv_smallatword_obj($code);
		return $this->storageLink('addf_inst')->sqlqueryGet(" WHERE `code`='{$code->get('sql')}'");
	}
    protected function pvtact_deleteAddfAssoc($id)
    {

        return $obj = $this->storageLink('addf_assoc')->delete($id);
        
    }
    
    // *********Работа с классом "пользователи"**********    
    protected function act_getClsUsers($assoc_id)
    {
        return $this->storageLink('addf_cls_users')->sqlqueryGet(" WHERE `assoc_id`='{$assoc_id->get('sql')}'");
    }
}
?>